/**
 * @file ConfigChanger.cpp
 * @author Jakub Trzaskoma
 *
 * Implementacja klasy odpowiadiadającej za zdalną zmianę aktualnego pliku konfiguracjnego poprzez port TCP.
 */

#include "ConfigChanger.h"
#include "Log.h"
#include "FileList.h"
#include "structures.h"
#include <stdlib.h>

namespace tftp_server
    {

    ConfigChanger::ConfigChanger()
	{

	}

    ConfigChanger::~ConfigChanger()
	{
	close(sock);
	}

    ConfigChanger::ConfigChanger(bool arg_, int port_, const char* password_)
	{
	if (arg_ == true)
	    {
	    ConfigChangerArguments arg;
	    arg.port = port_;
	    strcpy(arg.password, password_);
	    threadHandle
		    = pthread_create(&threadId, NULL, &runFunc, &arg);
	    sleep(1);
	    }
	}

    void *ConfigChanger::runFunc(void* arg)
	{
	ConfigChanger configChanger;
	ConfigChangerArguments tmp1 = *((ConfigChangerArguments*) (arg));
	Loger::getInstance().send(Log("ConfigChanger: Start listining!", 3));
	configChanger.run(tmp1.port, tmp1.password);
	return NULL;
	}

    int tftp_server::ConfigChanger::receive(int sock_, char *buff_)
	{
	int result;
	if (buff_[0] == '\n')
	    return 0;
	if ((result = read(sock_, buff_, sizeof(buff_))) == -1)
	    Loger::getInstance().send(Log("ConfigChanger: Receive error!", 2));
	return result;
	}
    int tftp_server::ConfigChanger::send(int sock_, char *buff_, int size_)
	{
	int result;
	if ((result = write(sock_, buff_, size_)) == -1)
	    Loger::getInstance().send(Log("ConfigChanger: Send error!", 2));

	return result;
	}
    bool tftp_server::ConfigChanger::compare(char *left_, char *right_)
	{
	while (*left_ != '\0')
	    {
	    if (*left_ != *right_)
		return false;
	    left_++;
	    right_++;
	    }
	if (*right_ == '\n')
	    return true;
	else
	    return false;
	}
    void tftp_server::ConfigChanger::getFilename(char *buff_, char *filename_)
	{
	while (*buff_ != '\n')
	    {
	    *filename_ = *buff_;
	    filename_++;
	    buff_++;
	    }
	*filename_ = '\0';
	}

    void ConfigChanger::run(int port_, char* password_)
	{
	char filename[256];
	char info[] = "Config Changer for tftp server. Enter password:\n";
	char info_password_ok[] =
		"Access granted. \nEnter config filename to load:\n";
	char info_password_fail[] = "Access denied. \n";
	char info_config_ok[] = "Config successfully loaded.\n";
	char info_config_fail[] = "Can't load config file. \n";
	struct sockaddr_in server;
	int msgsock, rval;
	char buf[1024];
	sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock == -1)
	    Loger::getInstance().send(Log(
		    "ConfigChanger: Making socket error!", 2));
	server.sin_family = AF_INET;
	server.sin_addr.s_addr = INADDR_ANY;
	server.sin_port = htons(port_);
	if (bind(sock, (struct sockaddr*) ((((&server)))), sizeof server) == -1)
	    Loger::getInstance().send(Log(
		    "ConfigChanger: Binding socket error!", 2));
	listen(sock, 3);
	do
	    {
	    msgsock = accept(sock, NULL, NULL);
	    if (msgsock == -1)
		Loger::getInstance().send(
			Log("ConfigChanger: Accept error!", 2));
	    else
		do
		    {
		    for (unsigned int i = 0; i < sizeof(buf); i++)
			buf[i] = 0;
		    //rval = receive(msgsock, buf);

			send(msgsock, info, sizeof(info));
			rval = receive(msgsock, buf);
		    if (compare(password_, buf))
			{
			send(msgsock, info_password_ok,
				sizeof(info_password_ok));
			rval = receive(msgsock, buf);
			getFilename(buf, filename);
			if (FileList::getInstance().setConfigFile(string(
				filename)))
			    {
				Loger::getInstance().send(Log("ConfigChanger: Loaded config file: " + string(filename), 3));
			    send(msgsock, info_config_ok,
				    sizeof(info_config_ok));
			    }
			else
			    send(msgsock, info_config_fail,
				    sizeof(info_config_fail));
			}
		    else if (rval != 0)
			send(msgsock, info_password_fail,
				sizeof(info_password_fail));
		    }
		while (rval != 0);
	    close(msgsock);
	    }
	while (1);
	}

    }
